﻿using System;
using System.Linq;
using ILMerging;
using NAnt.Core;
using NAnt.Core.Attributes;
using NAnt.Core.Types;

namespace NantGoogleCode
{
	/// <summary>
	/// NOTE: if you want to use this task you have to copy ILMerge.exe 
	/// into the same directory as NantGoogleCode.dll, or it has to be on
	/// your PATH.
	/// </summary>
	[TaskName("ilmerge")]
	public class ILMergeTask : Task
	{
		private string _attributeFile;
		private string _excludeFile;
		private string _logFile;
		private string _outputFile;
		private string _keyFile;

		public ILMergeTask()
		{
			Kind = ILMerge.Kind.SameAsPrimaryAssembly.ToString();
		}	

		[BuildElement("assemblies", Required = true)]
		public FileSet Assemblies { get; set; }

		[TaskAttribute("librarypath")]
		public FileSet LibraryPath { get; set; }

		[TaskAttribute("kind")]
		[StringValidator(AllowEmpty = false)]
		public string Kind { get; set; }

		[TaskAttribute("closed")]
		[BooleanValidator()]
		public bool Closed { get; set; }

		[TaskAttribute("copyattributes")]
		[BooleanValidator()]
		public bool CopyAttributes { get; set; }

		[TaskAttribute("debuginfo")]
		[BooleanValidator()]
		public bool DebugInfo { get; set; }

		[TaskAttribute("internalize")]
		[BooleanValidator()]
		public bool Internalize { get; set; }	

		[TaskAttribute("shouldlog")]
		[BooleanValidator()]
		public bool ShouldLog { get; set; }

		[TaskAttribute("attributefile")]
		public string AttributeFile
		{
			get
			{
				return _attributeFile.IfNotNullOrEmpty(af => Project.GetFullPath(_attributeFile));
			}
			set
			{
				_attributeFile = value;
			}
		}

		[TaskAttribute("excludefile")]
		public string ExcludeFile
		{
			get
			{
				return _excludeFile.IfNotNullOrEmpty(ef => Project.GetFullPath(_excludeFile));
			}
			set
			{
				_excludeFile = value;
			}
		}

		[TaskAttribute("logfile")]
		public string LogFile
		{
			get
			{
				return _logFile.IfNotNullOrEmpty(lf => Project.GetFullPath(lf));
			}
			set
			{
				_logFile = value;
			}
		}

		[TaskAttribute("outputfile", Required = true)]
		public string OutputFile
		{
			get
			{
				return _outputFile.IfNotNullOrEmpty(of => Project.GetFullPath(_outputFile));
			}
			set
			{
				_outputFile = value;
			}
		}

		[TaskAttribute("snkfile")]
		public string SnkFile
		{
			get
			{
				return _keyFile.IfNotNullOrEmpty(kf => Project.GetFullPath(kf));
			}
			set
			{
				_keyFile = value;
			}
		}		

		protected override void ExecuteTask()
		{
			var merger = new ILMerge();
			merger.AttributeFile = AttributeFile;
			merger.Closed = Closed;
			merger.CopyAttributes = CopyAttributes;
			merger.DebugInfo = DebugInfo;
			merger.ExcludeFile = ExcludeFile;
			merger.Internalize = Internalize;
			merger.LogFile = LogFile;
			merger.Log = ShouldLog;
			merger.OutputFile = OutputFile;
			merger.KeyFile = SnkFile;

			try
			{
				merger.TargetKind = (ILMerge.Kind) Enum.Parse(typeof(ILMerge.Kind), Kind, true);
			}
			catch (ArgumentException)
			{
				throw new BuildException(String.Format("Property kind should be [{0}]", String.Join("|", Enum.GetNames(typeof(ILMerge.Kind)))));
			}

			merger.SetInputAssemblies(Assemblies.FileNames.Cast<string>().ToArray());

			merger.SetSearchDirectories(LibraryPath.IfNotNull(lp =>
				lp.FileNames.Cast<string>().ToArray(), new string[0]).
				Concat(new string[] { "." }).ToArray());

			try
			{
				this.Log(Level.Info, "Merging {0} assembl{1} to '{2}'.", Assemblies.FileNames.Count, (Assemblies.FileNames.Count != 1) ? "ies" : "y", OutputFile);
				merger.Merge();
			}
			catch (Exception e)
			{
				throw new BuildException("Failed to merge assemblies", e);
			}
		}
	}
}